#ifndef MsnSession_H
#define MsnSession_H

#include <vector>
#include <list>
#include <map>

#include <wx/event.h>
#include <wx/datetime.h>
#include <wx/timer.h>
#include <wx/font.h>
#include <wx/colour.h>

class SessionConnection;

class FileTransferConnection;

class FileTransferEntry;
class FileTransferManager;

class MsnMessage;
class InstantMessage;
class InviteMessage;

class P2PMessage;
class SLPMessage;

class MsnMessenger;

class LogWriter;


enum MsnSessionStatus
{
    DISCONNECTED,
	CONNECTING,
	CONNECTED
};

class MessageHolder
{
friend class MsnSession;

private:
	MsnMessage* message;
	time_t createTime;
	//1+, transaction ID
	//0,  waiting
	//-1, ACK received
	//-2, NAK received
	int ackID;

public:
	MessageHolder(MsnMessage* msg);
	~MessageHolder();
};

struct InstantMessageItem
{
	MsnSession* session;
	wxString contact;
	wxString content;
	wxColour color;
	wxFont font;
};

class MsnSession : public wxEvtHandler
{

typedef std::vector<wxString> StringList;

typedef std::list<MessageHolder*> MessageList;

typedef std::map<int, P2PMessage*> P2PMessageMap;

typedef std::map<wxString, FileTransferEntry*> FileTransferItemMap;

private:
    StringList contactList;
	SessionConnection* connection;
	MsnSessionStatus status;
	int transactionID;
	
	P2PMessageMap p2pMessageMap;

	//FileTransferItemMap fileTransferItemMap;

	MsnMessenger* messenger;

	FileTransferManager* ftManager;

	LogWriter* logWriter;

	MessageList waitingMessageList;

	wxMutex waitingMessageMutex;

public:
	MsnSession(MsnMessenger* mm);
	~MsnSession();

	void Close();

	bool IsAlive();

	bool IsConnected();

	SessionConnection* GetConnection(){return connection;}
	void SetConnection(SessionConnection* conn);

	MsnMessenger* GetMessenger(){return messenger;}

	FileTransferManager* GetFtManager(){return ftManager;}

	void SetTransactionID(int id){transactionID = id;}
	int GetTransactionID(){return transactionID;}

	std::vector<wxString>& GetContactList(){return contactList;}

	void AddContact(const wxString& contact);
	void RemoveContact(const wxString& contact);
	wxString GetContact(int index);

	unsigned int GetContactCount(){return (unsigned int)contactList.size();}

	bool IsForContact(const wxString& contact);
	bool HasContact(const wxString& contact);

	wxString GetSessionTitle();

public:
	void InviteContact(const wxString& contact);

	void SendControlMessage();

	void SendInstantMessage(const wxString& content);
	void SendInstantMessage(InstantMessage* msg);

	void SendMsnMessage(MsnMessage* msg);

/*
    void SendFileInviteMessage(const wxString& filePath);
	void SendFileAcceptMessage(const wxString& cookie);
	void SendFileDeclineMessage(const wxString& cookie);
	void SendFileCancelMessage(const wxString& cookie);
*/



	

	//p2p
	void SendP2PAckMessage(P2PMessage* msg);

	void SendP2PSessionInviteMessage(const wxString& filePath);
	
	void SendP2PSessionAcceptMessage(P2PMessage* reqMsg);	

	void SendP2PSessionDeclineMessage(P2PMessage* reqMsg);

	void SendP2PByeMessage(P2PMessage* reqMsg);

	void SendP2PFileDataMessage(const wxString& sessionID);

	void SendP2PDisplayPictureData(const wxString& sessionID);

	void SendP2PDisplayPictureRequest();

	void SendP2PDataPreparationMessage(const wxString& sessionID);

public:
	InstantMessage* MakeInstantMessage(const wxString& content);

	P2PMessage* MakeP2PACKMessage(P2PMessage* msg);

	SLPMessage* MakeSLPMessage(const wxString& method,
								const wxString& contentType, 
								const wxString& to, 
								const wxString& from, 
								const wxString& via, 
								int cseq, 
								const wxString& callID);

	SLPMessage* MakeSLPMessage(SLPMessage* reqMsg, const wxString& method, const wxString& contentType);

	P2PMessage* MakeP2PMessage(int sessionID, SLPMessage* slpMsg);

	//P2PMessage* MakeP2PDataMessage(int sessionID, char* buf, int len);
	P2PMessage* MakeP2PDataMessage(int sessionID, int msgID, int dataOffset, int dataSize, int msgLen, int flag, char* buf);

	/* 
	  generate something like: A175812B-337E-4C50-4280-AA2C176B5ACD
	*/
	wxString GeneratePseudoUUID();

public:
	//
	void OnConnectionClosed();

	void OnContactJoined(const wxString& passport);
	void OnContactListed(const wxString& passport);
	void OnContactLeft(const wxString& passport);

    void OnInstantMessageReceived(InstantMessage* msg);
    void OnControlMessageReceived(MsnMessage* msg);

	void OnACKReceived(int trID);

	void OnNAKReceived(int trID);


	void OnP2PMessageReceived(P2PMessage* msg);

	void OnP2PCompleteMessageReceived(P2PMessage* msg);
	
	void OnP2PSessionInviteReceived(P2PMessage* msg);

	void OnP2PSessionInviteDisplayPictureReceived(P2PMessage* msg);

	void OnP2PSessionAcceptReceived(P2PMessage* msg);

	void OnP2PTransferRequestReceived(P2PMessage* msg);

	void OnP2PTransferAcceptReceived(P2PMessage* msg);

	void OnP2PByeReceived(P2PMessage* msg);

	void OnP2PDeclineReceived(P2PMessage* msg);

	void OnP2PDataReceived(P2PMessage* msg);

	void OnP2PFileDataReceived(P2PMessage* msg);

	void OnP2PDataPreparationReceived(P2PMessage* msg);

/*
	void OnInvitationMessageReceived(InviteMessage* msg);

	void OnFileInviteReceived(InviteMessage* msg);
	void OnFileAcceptReceived(InviteMessage* msg);
	void OnFileCancelReceived(InviteMessage* msg);	
*/

	void FlushWaitingMessages();
	void CheckWaitingMessages();
	void ClearWaitingMessages();

	void PostEvent(wxEvent& event);

private:
	
	void InitLogWriter();

	wxString GenerateCookie();

	void LogInstantMessage(InstantMessage* msg);
	void SendMessageHolder(MessageHolder* holder);

	void AddWaitingMessage(MessageHolder* holder);
	MessageHolder* RemoveWaitingMessage(int ackID);


	P2PMessage* MergeSplitP2PMessage(P2PMessage* msg);

};

#endif


